/*******************************************************************************
 * Copyright (C) Marvell International Ltd. and its affiliates
 *
 * This software file (the "File") is owned and distributed by Marvell
 * International Ltd. and/or its affiliates ("Marvell") under the following
 * alternative licensing terms.  Once you have made an election to distribute the
 * File under one of the following license alternatives, please (i) delete this
 * introductory statement regarding license alternatives, (ii) delete the three
 * license alternatives that you have not elected to use and (iii) preserve the
 * Marvell copyright notice above.
 *
 ********************************************************************************
 * Marvell Commercial License Option
 *
 * If you received this File from Marvell and you have entered into a commercial
 * license agreement (a "Commercial License") with Marvell, the File is licensed
 * to you under the terms of the applicable Commercial License.
 *
 ********************************************************************************
 * Marvell GPL License Option
 *
 * If you received this File from Marvell, you may opt to use, redistribute and/or
 * modify this File in accordance with the terms and conditions of the General
 * Public License Version 2, June 1991 (the "GPL License"), a copy of which is
 * available along with the File in the license.txt file or by writing to the Free
 * Software Foundation, Inc., or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
 *
 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
 * DISCLAIMED.  The GPL License provides additional details about this warranty
 * disclaimer.
 *
 ********************************************************************************
 * Marvell GNU General Public License FreeRTOS Exception
 *
 * If you received this File from Marvell, you may opt to use, redistribute and/or
 * modify this File in accordance with the terms and conditions of the Lesser
 * General Public License Version 2.1 plus the following FreeRTOS exception.
 * An independent module is a module which is not derived from or based on
 * FreeRTOS.
 * Clause 1:
 * Linking FreeRTOS statically or dynamically with other modules is making a
 * combined work based on FreeRTOS. Thus, the terms and conditions of the GNU
 * General Public License cover the whole combination.
 * As a special exception, the copyright holder of FreeRTOS gives you permission
 * to link FreeRTOS with independent modules that communicate with FreeRTOS solely
 * through the FreeRTOS API interface, regardless of the license terms of these
 * independent modules, and to copy and distribute the resulting combined work
 * under terms of your choice, provided that:
 * 1. Every copy of the combined work is accompanied by a written statement that
 * details to the recipient the version of FreeRTOS used and an offer by yourself
 * to provide the FreeRTOS source code (including any modifications you may have
 * made) should the recipient request it.
 * 2. The combined work is not itself an RTOS, scheduler, kernel or related
 * product.
 * 3. The independent modules add significant and primary functionality to
 * FreeRTOS and do not merely extend the existing functionality already present in
 * FreeRTOS.
 * Clause 2:
 * FreeRTOS may not be used for any competitive or comparative purpose, including
 * the publication of any form of run time or compile time metric, without the
 * express permission of Real Time Engineers Ltd. (this is the norm within the
 * industry and is intended to ensure information accuracy).
 *
 ********************************************************************************
 * Marvell BSD License Option
 *
 * If you received this File from Marvell, you may opt to use, redistribute and/or
 * modify this File under the following licensing terms.
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 *	* Redistributions of source code must retain the above copyright notice,
 *	  this list of conditions and the following disclaimer.
 *
 *	* Redistributions in binary form must reproduce the above copyright
 *	  notice, this list of conditions and the following disclaimer in the
 *	  documentation and/or other materials provided with the distribution.
 *
 *	* Neither the name of Marvell nor the names of its contributors may be
 *	  used to endorse or promote products derived from this software without
 *	  specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *******************************************************************************/

#include "std_internal.h"

#include "lib/mv_pme.h"

struct event_counters counters[PME_MAX_EVENT_CNTS] = {0};

static int clk_mhz;

static uint32_t read_clock_mhz(void)
{
	char buffer[256], *endptr = NULL;
	FILE *file;
	uint32_t ret = 0;

	file = fopen("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq", "r");
	if (file == NULL)
		return ret;

	if (fgets(buffer, sizeof(buffer), file) != NULL)
		ret = strtoull(buffer, &endptr, 0) / 1000;

	fclose(file);

	pr_info("CPU MHZ: %u\n", ret);
	return ret;
}

int pme_ev_cnt_create(char *name, u32 max_cnt, int ext_print)
{
	int i;

	if (!clk_mhz)
		clk_mhz = read_clock_mhz();

	if (strlen(name) > (PME_MAX_NAME_SIZE - 1)) {
		pr_err("Event counter name too long!\n");
		return -EINVAL;
	}
	for (i = 0; i < PME_MAX_EVENT_CNTS; i++)
		if (!counters[i].in_use) {
			memset(&counters[i], 0, sizeof(counters[i]));
			snprintf(counters[i].name, sizeof(counters[i].name), "%s", name);
			counters[i].max_cnt = max_cnt;
			counters[i].ext_print = ext_print;
			counters[i].in_use = 1;
			break;
		}
	if (i == PME_MAX_EVENT_CNTS) {
		pr_err("Maximum number of event counters exceeded!\n");
		return -EIO;
	}

	pr_debug("Allocated event %d for %s\n", i, counters[i].name);
	return i;
}

void pme_ev_cnt_destroy(int cnt)
{
	counters[cnt].in_use = 0;
}

void pme_ev_cnt_dump(int cnt, int reset)
{
	struct event_counters	*ev_cnt = &counters[cnt];
	struct timeval		t_curr;
	u64			tmp;

	gettimeofday(&t_curr, NULL);

	tmp  = (t_curr.tv_sec - ev_cnt->t_last.tv_sec) * 1000000;
	tmp += (t_curr.tv_usec - ev_cnt->t_last.tv_usec);

	printf("Event: %s: Avg cycles: %d, burst: %.2f\n",
	       ev_cnt->name,
	       (int)(ev_cnt->usecs * clk_mhz / ev_cnt->evs_cnt),
	       (float)ev_cnt->evs_cnt / ev_cnt->trig_cnt);
	if (ev_cnt->ext_print)
		printf("\t%d calls for 0 pkts, max was: %d, est. perf: %dKpps\n",
		       (int)ev_cnt->zero_cnt,
		       (int)ev_cnt->max_evs,
		       (int)((ev_cnt->evs_cnt * 1000) / tmp));
	ev_cnt->usecs = ev_cnt->evs_cnt = ev_cnt->trig_cnt = ev_cnt->zero_cnt = 0;
	gettimeofday(&ev_cnt->t_last, NULL);
}
